package com.work.cos.util.thirdpay.alipay.util;

import com.work.cos.util.constants.Constants;
import com.work.cos.domain.vo.ComMemoryCacheContext;
import com.work.cos.util.thirdpay.alipay.sign.MD5;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import com.work.cos.util.thirdpay.alipay.config.AlipayConfig;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/* *
 * 类名：AlipaySubmit功能：支付宝各接口请求提交类详细：构造支付宝各接口表单HTML文本，获取远程HTTP数据版本：3.3日期：2012-08-13说明：
 * 以下代码只是为了方便商户测试而提供的样例代码，商户可以根据自己网站的需要，按照技术文档编写,并非一定要使用该代码。该代码仅供学习和研究支付宝接口使用，只是提供一个参考。
 */

public class AlipaySubmit
{

    /**
     * 支付宝提供给商户的服务接入网关URL(新)
     */
    private static final String ALIPAY_GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";

    /**
     * 生成签名结果
     * 
     * @param sPara
     *            要签名的数组
     * @return 签名结果字符串
     */
    public static String buildRequestMysign(Map<String, String> sPara)
    {
        String prestr = AlipayCore.createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        String mysign = "";
        if ("MD5".equals(AlipayConfig.sign_type))
        {
            mysign = MD5.sign(prestr, AlipayConfig.key, AlipayConfig.input_charset);
        }
        return mysign;
    }

    /**
     * 生成要请求给支付宝的参数数组
     * 
     * @param sParaTemp
     *            请求前的参数数组
     * @return 要请求的参数数组
     */
    private static Map<String, String> buildRequestPara(Map<String, String> sParaTemp)
    {
        // 除去数组中的空值和签名参数
        Map<String, String> sPara = AlipayCore.paraFilter(sParaTemp);
        // 生成签名结果
        String mysign = buildRequestMysign(sPara);

        // 签名结果与签名方式加入请求提交参数组中
        sPara.put("sign", mysign);
        sPara.put("sign_type", AlipayConfig.sign_type);

        return sPara;
    }

    /**
     * 建立请求，以表单HTML形式构造（默认）
     * 
     * @param sParaTemp
     *            请求参数数组
     * @param strMethod
     *            提交方式。两个值可选：post、get
     * @param strButtonName
     *            确认按钮显示文字
     * @return 提交表单HTML文本
     */
    public static String buildRequest(Map<String, String> sParaTemp, String strMethod, String strButtonName)
    {
        // 待请求参数数组
        Map<String, String> sPara = buildRequestPara(sParaTemp);
        
        System.out.println(sPara.toString());
        List<String> keys = new ArrayList<String>(sPara.keySet());

        StringBuffer sbHtml = new StringBuffer();

        sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\""
                + ALIPAY_GATEWAY_NEW
                + "_input_charset="
                + AlipayConfig.input_charset
                + "\" method=\""
                + strMethod
                + "\">");

        for (int i = 0; i < keys.size(); i++)
        {
            String name = (String) keys.get(i);
            String value = new String((String) sPara.get(name));

            sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" +value+ "\"/>");
        }

        // submit按钮控件请不要含有name属性
        sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
        sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");
          System.out.println(sbHtml.toString());
        return sbHtml.toString();
    }

    /**
     * 建立请求，以表单HTML形式构造，带文件上传功能
     * 
     * @param sParaTemp
     *            请求参数数组
     * @param strMethod
     *            提交方式。两个值可选：post、get
     * @param strButtonName
     *            确认按钮显示文字
     * @param strParaFileName
     *            文件上传的参数名
     * @return 提交表单HTML文本
     */
    public static String buildRequest(Map<String, String> sParaTemp, String strMethod, String strButtonName,
            String strParaFileName)
    {
        // 待请求参数数组
        Map<String, String> sPara = buildRequestPara(sParaTemp);
        List<String> keys = new ArrayList<String>(sPara.keySet());

        StringBuffer sbHtml = new StringBuffer();

        sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\"  enctype=\"multipart/form-data\" action=\""
                + ALIPAY_GATEWAY_NEW
                + "_input_charset="
                + AlipayConfig.input_charset
                + "\" method=\""
                + strMethod
                + "\">");

        for (int i = 0; i < keys.size(); i++)
        {
            String name = (String) keys.get(i);
            String value = (String) sPara.get(name);

            sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
        }

        sbHtml.append("<input type=\"file\" name=\"" + strParaFileName + "\" />");

        // submit按钮控件请不要含有name属性
        sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");

        return sbHtml.toString();
    }

    // /**
    // * 建立请求，以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
    // * 如果接口中没有上传文件参数，那么strParaFileName与strFilePath设置为空值
    // * 如：buildRequest("", "",sParaTemp)
    // * @param strParaFileName 文件类型的参数名
    // * @param strFilePath 文件路径
    // * @param sParaTemp 请求参数数组
    // * @return 支付宝处理结果
    // * @throws Exception
    // */
    // public static String buildRequest(String strParaFileName, String strFilePath,Map<String, String> sParaTemp)
    // throws Exception {
    // //待请求参数数组
    // Map<String, String> sPara = buildRequestPara(sParaTemp);
    //
    // HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler.getInstance();
    //
    // HttpRequest request = new HttpRequest(HttpResultType.BYTES);
    // //设置编码集
    // request.setCharset(AlipayConfig.input_charset);
    //
    // request.setParameters(generatNameValuePair(sPara));
    // request.setUrl(ALIPAY_GATEWAY_NEW+"_input_charset="+AlipayConfig.input_charset);
    //
    // HttpResponse response = httpProtocolHandler.execute(request,strParaFileName,strFilePath);
    // if (response == null) {
    // return null;
    // }
    //
    // String strResult = response.getStringResult();
    //
    // return strResult;
    // }

    /**
     * MAP类型数组转换成NameValuePair类型
     * 
     * @param properties
     *            MAP类型数组
     * @return NameValuePair类型数组
     */
    private static NameValuePair[] generatNameValuePair(Map<String, String> properties)
    {
        NameValuePair[] nameValuePair = new BasicNameValuePair[properties.size()];
        int i = 0;
        for (Map.Entry<String, String> entry : properties.entrySet())
        {
            nameValuePair[i++] = new BasicNameValuePair(entry.getKey(), entry.getValue());
        }

        return nameValuePair;
    }

    /**
     * 用于防钓鱼，调用接口query_timestamp来获取时间戳的处理函数 注意：远程解析XML出错，与服务器是否支持SSL等配置有关
     * 
     * @return 时间戳字符串
     * @throws IOException
     * @throws DocumentException
     * @throws MalformedURLException
     */
    public static String query_timestamp() throws MalformedURLException, DocumentException, IOException
    {

        // 构造访问query_timestamp接口的URL串
        String strUrl = ALIPAY_GATEWAY_NEW
                + "service=query_timestamp&partner="
                + AlipayConfig.partner
                + "&_input_charset"
                + AlipayConfig.input_charset;
        StringBuffer result = new StringBuffer();

        SAXReader reader = new SAXReader();
        Document doc = reader.read(new URL(strUrl).openStream());

        List<Node> nodeList = doc.selectNodes("//alipay/*");

        for (Node node : nodeList)
        {
            // 截取部分不需要解析的信息
            if (node.getName().equals("is_success") && node.getText().equals("T"))
            {
                // 判断是否有成功标示
                List<Node> nodeList1 = doc.selectNodes("//response/timestamp/*");
                for (Node node1 : nodeList1)
                {
                    result.append(node1.getText());
                }
            }
        }

        return result.toString();
    }

    /**
     * 构造模拟远程HTTP的POST请求，获取支付宝的返回XML处理结果
     * 
     * @param sParaTemp
     *            请求参数数组
     * @return 支付宝返回XML处理结果
     * @throws UnsupportedEncodingException
     * @throws Exception
     */
    public static String sendPostInfo(Map<String, String> sParaTemp) throws UnsupportedEncodingException
    {
        // 待请求参数数组
        Map<String, String> signedPara = buildRequestPara(sParaTemp);

        String result = null;
        // try {
        // result = Request.Get(ALIPAY_GATEWAY_NEW).execute().returnContent().asString();
        // } catch (IOException e) {
        // e.printStackTrace();
        // }

        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(ALIPAY_GATEWAY_NEW);
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        for (Map.Entry<String, String> entry : signedPara.entrySet())
        {
            nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }
        httpPost.setEntity(new UrlEncodedFormEntity(nvps));
        try
        {
            CloseableHttpResponse response = httpclient.execute(httpPost);
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // HttpRequest request = new HttpRequest(HttpResultType.BYTES);
        // //设置编码集
        // request.setCharset(AlipayConfig.input_charset);
        // request.setParameters(generatNameValuePair(sPara));
        // request.setUrl(ALIPAY_GATEWAY_NEW );
        // request.setMethod(HttpRequest.METHOD_GET);
        // HttpResponse response;
        // try {
        // response = httpProtocolHandler.execute(request,"","");
        // if (response == null) {
        // return null;
        // }
        // } catch (HttpException e) {
        // return null;
        // } catch (IOException e) {
        // return null;
        // }

        return result;
    }

    /**
     * 构造即时到账批量退款有密接口
     * 
     * @param sParaTemp
     *            请求参数集合
     * @return 支付宝返回表单提交HTML信息
     * @throws UnsupportedEncodingException
     * @throws Exception
     */
    public static String refund_fastpay_by_platform_nopwd(Map<String, String> sParaTemp)
            throws UnsupportedEncodingException
    {

        // 增加基本配置
        sParaTemp.put("service", "refund_fastpay_by_platform_nopwd");
        sParaTemp.put("partner", AlipayConfig.partner);
        sParaTemp.put("notify_url", ComMemoryCacheContext.getObjectFromMemory(Constants.URL_APP_ROOT)
                + AlipayConfig.refund_notify_url);
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
        // String strButtonName="退款";
        // return AlipaySubmit.buildForm(sParaTemp, ALIPAY_GATEWAY_NEW,"get",strButtonName);
        return AlipaySubmit.sendPostInfo(sParaTemp);
    }

}
